package com.idroc.endpoint.impl;

import java.net.InetSocketAddress;
import java.util.TreeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import com.idroc.endpoint.Endpoint;
import com.idroc.endpoint.Serializer;
import com.idroc.rpc.RPCFactory;
import com.idroc.rpc.RPCProvider;

/**
 * 主端点
 * @author 詹都林 (zhandl@hainan.net)  
 * Aug 14, 2009 2:22:19 PM
 * @memo:
 */
public class MasterEndpoint implements Endpoint {
	
	private static final Logger log = LoggerFactory.getLogger(MasterEndpoint.class);

	public static final String MASTER_ENDPOINT = "master_endpoint";
	public static final String SLAVE_ENDPOINT_COLLECTION = "slave_endpoint_collection";
	
	private Integer epNo = null;
	private String host = null;
	private Integer port = null;

	private transient int hashCode = 0;
	
	private TreeMap<Integer, Endpoint> slaves = null;
	
	private transient Serializer serializer = null;
	
	private transient RPCProvider rpcProvider = null;
	
	public MasterEndpoint() {}

	public MasterEndpoint(Integer epNo, String host, Integer port, Serializer serializer) {
		
		this.epNo = epNo;
		this.host = host;
		this.port = port;
		this.serializer = serializer;
		
		initSlaves();
		
		// 对外提供rpc服务
		InetSocketAddress endpoint = new InetSocketAddress(host, port);
		rpcProvider = RPCFactory.bindEndpoint(endpoint);
		rpcProvider.bind(Endpoint.class, this);
	}
	
	/**
	 * 初始化从端点
	 */
	private void initSlaves() {
		try {
			slaves = new TreeMap<Integer, Endpoint>();
			TreeMap<Integer, Endpoint> old = (TreeMap<Integer, Endpoint>) serializer.load(SLAVE_ENDPOINT_COLLECTION);
			if (old.size() > 0) {			
				for (Integer no : old.keySet()) {
					try {
						Endpoint ep = new ProxyEndpoint(old.get(no));
						if (ep.checkAlive() && !this.equals(ep)) {
							slaves.put(ep.getEndpointNo(), ep);
						}
					} catch (Exception ex) {
						log.error("主端点(MasterEndpoint)初始化从端点异常", ex);
					}
				}
			}
			slaves.put(epNo, this);
			serializer.save(SLAVE_ENDPOINT_COLLECTION, slaves);
		} catch (Exception ex) {
			log.info("主端点(MasterEndpoint)无法加载之前的从端点", ex);
		}
	}
	
	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#addEndpoint(com.idroc.endpoint.Endpoint, com.idroc.endpoint.Endpoint)
	 */
	public boolean addEndpoint(Endpoint master, Endpoint newSlave) {
		
		if (this.equals(master) && newSlave.checkAlive()) {
			if (this.equals(newSlave)) {
				slaves.put(this.getEndpointNo(), this);
			} else {
				Endpoint proxy = new ProxyEndpoint(newSlave);
				slaves.put(proxy.getEndpointNo(), proxy);
			}
			boolean saved = this.serializer.save(SLAVE_ENDPOINT_COLLECTION, slaves);
			log.debug("主端点(MasterEndpoint)增加端点:{}, newSlave:{}", saved, newSlave); 
			return saved;
		} else {
			log.debug("主端点(MasterEndpoint)增加端点");
		}
		return false;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#checkAlive()
	 */
	public boolean checkAlive() {

		return true;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#dropEndpoint(com.idroc.endpoint.Endpoint, java.lang.Integer)
	 */
	public boolean dropEndpoint(Endpoint master, Integer epNo) {

		if (this.equals(master)) {
			Endpoint removed = this.slaves.remove(epNo);
			if (null != removed) {
				boolean saved = this.serializer.save(SLAVE_ENDPOINT_COLLECTION, slaves);
				log.debug("主端点(MasterEndpoint)移除端点:{}, epNo:{}", saved, epNo); 
			}
			return true;
		}
		return false;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#getEndpointHost()
	 */
	public String getEndpointHost() {

		return host;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#getEndpointNo()
	 */
	public Integer getEndpointNo() {

		return epNo;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#getEndpointPort()
	 */
	public Integer getEndpointPort() {
		
		return port;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#getMasterEndpoint()
	 */
	public Endpoint getMasterEndpoint() {

		return this;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#getSlaveEndpoint()
	 */
	public TreeMap<Integer, Endpoint> getSlaveEndpoint() {
		
		log.debug("当前从端点集合:{}", slaves);
		return slaves;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#isMasterEndpoint()
	 */
	public boolean isMasterEndpoint() {

		log.debug("this is a master Endpoint");
		return true;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#rebuildMasterEndpoint(boolean)
	 */
	public Endpoint rebuildMasterEndpoint(boolean nested) {

		log.debug("rebuild master Endpoint with [THIS]");
		return this;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#registerEndpoint(com.idroc.endpoint.Endpoint)
	 */
	public boolean registerEndpoint(Endpoint ep) {

		if (ep.checkAlive()) {
			
			ProxyEndpoint proxy = new ProxyEndpoint(ep);
			this.slaves.put(proxy.getEndpointNo(), proxy);
			this.serializer.save(SLAVE_ENDPOINT_COLLECTION, slaves);
			for (Integer no : slaves.keySet()) {
				try {
					
					Endpoint slave = slaves.get(no);
					slave.addEndpoint(this, ep);
					log.debug("主端点命令从端点[{}]增加一个新的从端点[{}]", slave, ep);
				} catch (Exception ex) {
					log.error("主端点注册端点异常", ex);
				}
			}
			log.debug("主端点(MasterEndpoint)注册一个从端点:{}", ep);
			return true;
		}
		return false;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#replaceMasterEndpoint(com.idroc.endpoint.Endpoint)
	 */
	public boolean replaceMasterEndpoint(Endpoint ep) {
		
		log.debug("replaceMasterEndpoint:{}", ep);
		return false;
	}

	/*
	 * 
	 * @see com.idroc.endpoint.Endpoint#unregisterEndpoint(java.lang.Integer)
	 */
	public boolean unregisterEndpoint(Integer epNo) {

		Endpoint ep = this.slaves.remove(epNo);
		if (null != ep) {
			this.serializer.save(SLAVE_ENDPOINT_COLLECTION, slaves);
			for (Integer no : slaves.keySet()) {
				try {
					Endpoint slave = slaves.get(no);
					slave.dropEndpoint(this, ep.getEndpointNo());
				} catch (Exception ex) {
					log.error("主端点(MasterEndpoint)取消从端点异常", ex);
				}
			}
			ep.dropEndpoint(this, epNo);
			log.debug("主端点(MasterEndpoint)取消一个端点:{}", epNo);
			return true;
		}
		return false;
	}
	
	/**
	 * 当 编号相同, 主机IP相同, 端口相同, 认为两个端点相同
	 */
	@Override
	public boolean equals(Object obj) { 
		
		if (null == obj) {
			return false;
		}
		if (obj instanceof Endpoint) {
			Endpoint ep = (Endpoint)obj;
			Integer no = ep.getEndpointNo();
			String host = ep.getEndpointHost();
			Integer port = ep.getEndpointPort();
			return epNo.equals(no) && this.host.equals(host) && this.port.equals(port);
		} else {
			return false;
		}
	}

	@Override
	public int hashCode() { 
		
		if (hashCode == 0) {
			
			hashCode = 17;
			hashCode = 37 * hashCode + epNo.hashCode();
			hashCode = 37 * hashCode + host.hashCode();
			hashCode = 37 * hashCode + port.hashCode();
		}
		return hashCode;
	}
	
	@Override
	public String toString() {
		
		StringBuilder sb = new StringBuilder();
		sb.append("MasterEndpoint[");
		sb.append("epNo:").append(epNo).append(",");
		sb.append("host:").append(host).append(",");
		sb.append("port:").append(port);
		sb.append("]");
		return sb.toString();
	}

}
